package com.googlecode.animator.data.objects3d
{
	import com.googlecode.animator.data.IValueObject;
	import com.googlecode.animator.data.PositionObject3D;
	import com.googlecode.animator.data.markers.HideMarkerVO;
	import com.googlecode.animator.data.markers.KeyframeVO;
	import com.googlecode.caurina.transitions.Tweener;
	
	import flash.events.Event;
	import flash.utils.Dictionary;
	
	import mx.collections.ArrayCollection;
	import mx.collections.Sort;
	import mx.collections.SortField;
	
	import org.papervision3d.core.math.Number3D;
	
	/**
	 * The Object3DVO carries all the data relating to an object 
	 * in the scene, including that relating to its materials and any associated markers.
	 * Default data are added so that a standard object can be produced.
	 * Only its name, type and material(s) need be defined. 
	 *  
	 * @author ~martin
	 * 
	 */
	public class Object3DVO extends PositionObject3D implements IObject3DVO
	{		
		
		public var rotationX:Number = 0;
		
		public var rotationY:Number = 0;
		
		public var rotationZ:Number = 0;
		
		public var scaleX:Number = 1;
		
		public var scaleY:Number = 1;
		
		public var scaleZ:Number = 1;
		
		public var visible:Boolean = true;
		
		public var tweens:Array = [];
		
		//public var keyframes:Dictionary = new Dictionary();
		
		private var _keyframes:Dictionary = new Dictionary();
		
		public var hideMarkers:Dictionary = new Dictionary();
		
		public function Object3DVO()
		{
			addEventListener("calculateTweens", calculateTweens);
		}
		
		public function set keyframes(kFrames:Dictionary):void
		{
			_keyframes = kFrames;
			
			calculateTweens();
		}
		
		public function get keyframes():Dictionary
		{			
			return _keyframes;
		}
		
		override public function clone(src:* = null):IValueObject
		{
			if(src == null)
			{
				src = super.clone(new Object3DVO());
			}else
			{
				src = super.clone(src);
			}			
			
			for each(var hMarker:HideMarkerVO in this.hideMarkers)
			{
				src.hideMarkers[hMarker.id] = hMarker.clone();
			}
			
			for each(var keyframe:KeyframeVO in this.keyframes)
			{
				src.keyframes[keyframe.id] = keyframe.clone();
			}
			
			for(var i:uint=0; i<this.tweens.length; i++)
			{
				src.tweens[i] = (this.tweens[i] as Number3D).clone();
			}

			src.rotationX = this.rotationX;
			src.rotationY = this.rotationY;
			src.rotationZ = this.rotationZ;
			src.scaleX = this.scaleX;
			src.scaleY = this.scaleY;
			src.scaleZ = this.scaleZ;
			src.visible = this.visible;
			
			return src;
		}
		
		override public function toXML(src:XML = null):XML
		{	
			if(src == null)
			{
				src = super.toXML(<object3D name={this.name} label={this.label}></object3D>);
				
			}else
			{
				src = super.toXML(src);
			}	

			src.appendChild(<rotationX>{this.rotationX}</rotationX>);
			src.appendChild(<rotationY>{this.rotationY}</rotationY>);
			src.appendChild(<rotationZ>{this.rotationY}</rotationZ>);		
			
			src.appendChild(<scaleX>{this.scaleX}</scaleX>);
			src.appendChild(<scaleY>{this.scaleY}</scaleY>);
			src.appendChild(<scaleZ>{this.scaleZ}</scaleZ>);
						
			src.appendChild(<visible>{this.visible}</visible>);
			
			src.appendChild(<hideMarkers></hideMarkers>);
					
			for each(var hideMarker:HideMarkerVO in hideMarkers)
			{				
				src.hideMarkers.appendChild(hideMarker.toXML());
			}
			
			src.appendChild(<keyFrames></keyFrames>);
			
			for each(var keyFrame:KeyframeVO in keyframes)
			{				
				src.keyFrames.appendChild(keyFrame.toXML());
			}

			return src;
		}
		
		override public function fromXML(src:XML):void
		{
			super.fromXML(src);

			this.rotationX = src.rotationX;
			this.rotationY = src.rotationY;
			this.rotationZ = src.rotationZ;
			/* this.scaleX = src.scaleX;
			this.scaleY = src.scaleY;
			this.scaleZ = src.scaleZ; */
			this.visible = visible;
			
			var hideMarkers:Array = new Array();;
			var hMarker:HideMarkerVO;	
			
			for each(var hideMarker:XML in src.hideMarkers.HideMarker)
			{
				hMarker = new HideMarkerVO();
				hMarker.id = hideMarker.@id;
				hMarker.begin = hideMarker.begin;
				hMarker.end = hideMarker.end;
				
				hideMarkers.push(hMarker);
				
			}		
			
			//var keyFrames:Dictionary = new Dictionary();
			var kFrame:KeyframeVO;
			
			for each(var keyFrame:XML in src.keyFrames.KeyFrame)
			{
				kFrame = new KeyframeVO();
				kFrame.object3DName = this.name;
				kFrame.id = keyFrame.@id;
				kFrame.isDraggable = keyFrame.isDraggable;

				var positions:Array = (keyFrame.position as XMLList)[0].toString().split(" ");
				kFrame.position = new Number3D(positions[0], positions[1], positions[2]);
				
				kFrame.time = keyFrame.time;

				this.keyframes[kFrame.id] = kFrame;
			}
		}
		
		public function calculateTweens():void
		{
			var keyframesAC:ArrayCollection = new ArrayCollection();
			
			for each(var kf:KeyframeVO in this.keyframes)
			{
				keyframesAC.addItem(kf.clone());
			}
			
			//Sort keyFrames time ascending
			var s:Sort = new Sort();
			var sF:SortField = new SortField("time", true);
			sF.numeric = true;				
			s.fields = [sF];
			keyframesAC.sort = s;
			keyframesAC.refresh();
			
			//Tween
			if(keyframesAC.length < 1)
			{
				return;
			}
			
			var evt:Event = new Event("event");
			var startPos:Number3D = ((keyframesAC[0] as KeyframeVO).position).clone();
			
			this.tweens = []; 
			
			this.tweens.push(startPos);
			
			for(var i:uint=0; i<keyframesAC.length-1; i++)
			{
				var currentPos:Number3D = (keyframesAC[i].position as Number3D);
				var nextPos:Number3D = (keyframesAC[i+1].position as Number3D);
				var t:uint = (keyframesAC[i+1].time - keyframesAC[i].time);

				if(t==0)
				{
					return;
				}
				
				Tweener.addTween(currentPos, {x:nextPos.x, y:nextPos.y, z:nextPos.z, time:t, useFrames:true, transition:"linear"});
				
				for(var j:uint=0; j<t; j++)
				{
					Tweener.onEnterFrame(evt);
					
					this.tweens.push(currentPos.clone());
					
				}
				
			}

			Tweener.removeTweens(currentPos);

		}
	}
}